Аутентификация пользователя
===========================

Наше приложение должно различать владельца системы и гостей. Поэтому
мы должны реализовать функцию
[пользовательской аутентификации](/doc/guide/ru/topics.auth).

Вы, возможно, заметили, что каркас приложения уже реализует аутентификацию,
проверяя, являются ли имя пользователя и пароль значениями `demo` и `admin`.
В этом разделе мы изменим соответствующий код так, чтобы аутентификация
происходила посредством таблицы `User` БД.

Аутентификация пользователя выполняется в классе, который реализует интерфейс
[IUserIdentity]. Для этой цели каркас приложения использует класс `UserIdentity`.
Класс находится в файле `/wwwroot/blog/protected/components/UserIdentity.php`.

> Tip|Подсказка: В соответствии с соглашением, название файла класса должно быть
> таким же как имя класса плюс расширение `.php`. Можно обратиться к классу, используя
> [псевдоним пути](/doc/guide/ru/basics.namespace). Например, мы
> можем обратиться к классу `UserIdentity` используя псевдоним
> `application.components.UserIdentity`. Многие методы API в Yii могут распознать
> псевдонимы пути (например, [Yii::createComponent()|YiiBase::createComponent]).
> Это позволяет избежать использования абсолютных путей в коде, которые создают
> неприятности при развертывании приложения.

Модифицируем класс `UserIdentity` следующим образом:

~~~
[php]
<?php
class UserIdentity extends CUserIdentity
{
	private $_id;

	public function authenticate()
	{
		$username=strtolower($this->username);
		$user=User::model()->find('LOWER(username)=?',array($username));
		if($user===null)
			$this->errorCode=self::ERROR_USERNAME_INVALID;
		else if(!$user->validatePassword($this->password))
			$this->errorCode=self::ERROR_PASSWORD_INVALID;
		else
		{
			$this->_id=$user->id;
			$this->username=$user->username;
			$this->errorCode=self::ERROR_NONE;
		}
		return $this->errorCode==self::ERROR_NONE;
	}

	public function getId()
	{
		return $this->_id;
	}
}
~~~

В методе `authenticate()` мы используем класс `User` для поиска строки в
таблице `tbl_user`, в которой значение поля `username` такое же, как полученное
имя пользователя без учета регистра. Помните, что класс `User` был создан,
используя инструмент `gii` в предыдущем разделе. Поскольку класс `User`
наследуется от класса [CActiveRecord], мы можем использовать
[возможности ActiveRecord](/doc/guide/ru/database.ar)
для того, чтобы обращаться к таблице `tbl_user` в ОО манере.

Для того, чтобы проверить, ввёл ли пользователь правильный пароль, мы вызываем
метод `validatePassword` класса `User`. Нам необходимо изменить файл
`/wwwroot/blog/protected/models/User.php` как показано ниже. Отметим, что
вместо хранения пароля в БД в явном виде, мы сохраняем его хеш. При проверке введённого пользователем пароля,
вместо сравнения паролей, мы должны сравнивать хеши. Для хеширования пароля и его проверки мы используем входящий
в Yii класс [CPasswordHelper].


~~~
[php]
class User extends CActiveRecord
{
	......
	public function validatePassword($password)
	{
		return CPasswordHelper::verifyPassword($password,$this->password);
	}

	public function hashPassword($password)
	{
		return CPasswordHelper::hashPassword($password);
	}
}
~~~

В классе `UserIdentity` мы также переопределяем метод `getId()`, который
возвращает значение `id` пользователя, найденного в таблице `tbl_user`.
Родительская реализация возвратила бы имя пользователя вместо `id`. И
`username` и `id` будут сохранены в сессии и доступны через
`Yii::app()->user` в любом месте нашего кода.


> Tip|Подсказка: В классе `UserIdentity` мы используем [CUserIdentity]
> без явного подключения соответствующего файла. Это возможно т.к.
> [CUserIdentity] — один из классов ядра фреймворка Yii. Yii будет
> автоматически подключать файл класса для любого класса ядра, когда к нему
> обратятся впервые. То же возможно с классом `User` т.к. он расположен в директории
> `/wwwroot/blog/protected/models`, которая была добавлена к параметру
> `include_path` PHP в конфигурации приложения следующим образом:
>
> ~~~
> [php]
> return array(
>     …
>     'import'=>array(
>         'application.models.*',
>         'application.components.*',
>     ),
>     …
> );
> ~~~
>
> Конфигурация выше говорит, что любой класс, файл которого расположен
> в директории `/wwwroot/blog/protected/models` или
> `/wwwroot/blog/protected/components`, будет автоматически подключен, когда к
> классу обратятся впервые.

Класс `UserIdentity` используется классом `LoginForm` для аутентификации
пользователя, основанной на введенных имени и пароле, полученных на странице
входа в систему. Следующий фрагмент кода показывает как используется класс `UserIdentity`:

~~~
[php]
$identity=new UserIdentity($username,$password);
$identity->authenticate();
switch($identity->errorCode)
{
	case UserIdentity::ERROR_NONE:
		Yii::app()->user->login($identity);
		break;
	…
}
~~~


> Info|Информация: Люди часто путаются в идентификации (identity) и компоненте
> приложения `user`. Первая представляет способ выполнения аутентификации, в то
> время как последний используется, чтобы представить информацию, связанную с
> текущим пользователем. У приложения может быть только один компонент `user`,
> но один или несколько классов идентификации, в зависимости от того, какую
> аутентификацию поддерживает приложение. При аутентификации,
> экземпляр идентификации может передать некоторую информацию компоненту `user`.
> Эта информация будет глобально доступна через компонент `user`.

Чтобы проверить изменённый класс `UserIdentity`, мы можем открыть адрес
`http://www.example.com/blog/index.php` и попытаться войти с именем
пользователя и паролем, которые мы храним в таблице `tbl_user`. Если мы используем
базу данных, предоставленную
[демонстрационной версией блога](http://www.yiiframework.com/demos/blog/),
мы можем войти с именем пользователя `demo` и паролем `demo`. Отметим, что эта
система блога не обеспечивает функцию управления пользователями. Поэтому
пользователь не может изменить свою учетную запись или создать новую через веб-интерфейс.
Функцию управления пользователями можно рассматривать как будущее расширение к
приложению блога.